package com.ojoin.trade.common.web.controller;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ojoin.trade.common.Constants;
import com.ojoin.trade.common.spring.RedisCache;
import com.ojoin.trade.common.utils.CommonUtils;
import com.ojoin.trade.common.utils.PrettyMemoryUtils;
import com.ojoin.trade.common.utils.TimeUtils;
import com.ojoin.trade.common.web.domain.EhCacheStatisticsVO;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.Cache.ValueWrapper;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;

@Controller
@RequestMapping("/monitor/ehcache")
public class CacheMonitorController extends SimpleBaseController {

    @Autowired
    private CacheManager cacheManager;

    @Autowired
    private org.apache.shiro.cache.CacheManager shiroCacheManager;

    private final String SHIRO_CACHE_AUTHORIZATIONCACHE ="authorizationShiroCache";

    @ResponseBody
    @RequestMapping("list")
    @RequiresRoles("sys_admin")
    public List<EhCacheStatisticsVO> index() {
        Collection<String> cacheNames = cacheManager.getCacheNames();
        List<String> cacheNameList = CommonUtils.cast(cacheNames);
        List<EhCacheStatisticsVO> ret = new ArrayList();
        for (int i = 0, length = cacheNames.size(); i < length; i++) {
            String cacheName = cacheNameList.get(i);
            EhCacheStatisticsVO es = new EhCacheStatisticsVO();
            es.setCacheName(cacheName);
            ret.add(es);
        }

        EhCacheStatisticsVO shiroCache = new EhCacheStatisticsVO();
        shiroCache.setCacheName(SHIRO_CACHE_AUTHORIZATIONCACHE);
        ret.add(shiroCache);
        return ret;
    }

    @ResponseBody
    @RequestMapping("{cacheName}/details")
    @RequiresRoles("sys_admin")
    public List details(@PathVariable("cacheName") String cacheName,
                        @RequestParam(value = "searchText", required = false, defaultValue = "") String searchText) {
        List showKeys = Lists.newArrayList();
        if (cacheName.equals(SHIRO_CACHE_AUTHORIZATIONCACHE)) {
            com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache<byte[], Object> cache = (com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache) shiroCacheManager.getCache("com.ojoin.trade.common_core.web.shiro.SystemAuthorizingRealm.authorizationCache");
            Set<byte[]> allKeys = cache.keys();
            for (byte[] key : allKeys) {
                String keyStr=new String(key);
                if (keyStr.contains(searchText)) {
                    showKeys.add(keyStr);
                }
            }
        } else {

            Cache cache = cacheManager.getCache(cacheName);
            List allKeys = ((RedisCache) cache).getKeys();
            for (Object key : allKeys) {
                if (key.toString().contains(searchText)) {
                    showKeys.add(key);
                }
            }
        }
        return showKeys;
    }

    @RequestMapping("{cacheName}/{key}/details")
    @ResponseBody
    @RequiresRoles("sys_admin")
    public Object keyDetail(@PathVariable("cacheName") String cacheName, @PathVariable("key") String key) {
        ValueWrapper element = null;
        int expiration = 0;
        try {
            String dekey = URLDecoder.decode(key, Constants.ENCODING);
            if (cacheName.equals(SHIRO_CACHE_AUTHORIZATIONCACHE)) {
                com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache<Object, Object> cache = (com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache) shiroCacheManager.getCache("com.ojoin.trade.common_core.web.shiro.SystemAuthorizingRealm.authorizationCache");
                final  SimpleAuthorizationInfo obj=(SimpleAuthorizationInfo)cache.get(key);
                element=new ValueWrapper(){
                    @Override
                    public Object get() {
                        return obj;
                    }
                };
            } else {
                Cache cache = cacheManager.getCache(cacheName);
                expiration = ((RedisCache) cache).getExpiration();
                element = cache.get(dekey);
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        if (null == element) {
            return Maps.newHashMap();
        }
        Map<String, Object> data = Maps.newHashMap();
        Object value = element.get();
        data.put("objectValue", value);
        data.put("size", PrettyMemoryUtils.prettyByteSize(getSerializedSize(value)));

        if (expiration == 0) {
            data.put("expirationTime", "不过期");
        } else {
            data.put("expirationTime", TimeUtils.toZhTimeString(expiration * 1000));
        }
        return data;

    }

    @RequestMapping("{cacheName}/{key}/delete")
    @ResponseBody
    @RequiresRoles("sys_admin")
    public Object delete(@PathVariable("cacheName") String cacheName, @PathVariable("key") String key) {
        if (cacheName.equals(SHIRO_CACHE_AUTHORIZATIONCACHE)) {
            com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache<Object, Object> cache = (com.ojoin.trade.common.web.shiro.cache.JedisCacheManager.JedisCache) shiroCacheManager.getCache("com.ojoin.trade.common_core.web.shiro.SystemAuthorizingRealm.authorizationCache");
            cache.remove(key);
        } else {

            Cache cache = cacheManager.getCache(cacheName);
            cache.evict(key);
        }
        return "操作成功！";

    }

    @RequestMapping("{cacheName}/clear")
    @ResponseBody
    @RequiresRoles("sys_admin")
    public Object clear(@PathVariable("cacheName") String cacheName) {

        if (cacheName.equals(SHIRO_CACHE_AUTHORIZATIONCACHE)) {

            shiroCacheManager.getCache("com.ojoin.trade.common_core.web.shiro.SystemAuthorizingRealm.authorizationCache").clear();

        } else {

            Cache cache = cacheManager.getCache(cacheName);
            cache.clear();
        }
        return "操作成功！";

    }

    public final long getSerializedSize(Object value) {
        if (!(isSerializable(value))) {
            return 0L;
        }
        long size = 0L;
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(bout);
            oos.writeObject(value);
            size = bout.size();
            long l1 = size;

            return l1;
        } catch (IOException e) {
        } finally {
            try {
                if (oos != null)
                    oos.close();
            } catch (Exception e) {
            }
        }

        return size;
    }

    public final boolean isSerializable(Object value) {
        return ((value instanceof Cloneable) || (value == null));
    }
}